package com.cty.aio;

import org.apache.log4j.Logger;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.util.concurrent.TimeUnit;

/**
 * @Auther: cty
 * @Date: 2020/4/18 16:48
 * @Description:
 * @version: 1.0
 */
public class AIOServer {
    Logger log = Logger.getLogger(AIOServer.class);
    // 定义线程池，提高服务端效率
    // private ExecutorService service;
    // 线程组
    // private AsynchronousChannelGroup group;
    // 服务端通道，针对服务端定义的通道
    private AsynchronousServerSocketChannel serverChannel;

    public AsynchronousServerSocketChannel getServerChannel() {
        return serverChannel;
    }

    public void setServerChannel(AsynchronousServerSocketChannel serverChannel) {
        this.serverChannel = serverChannel;
    }

    // 构造器
    public AIOServer(int port){
        init(9999);
    }

    // 初始化函数
    private void init(int port){
        try {
            System.out.println("Server is starting at port "+port+" ...");
            // 定义线程池长
            // service = Executors.newFixedThreadPool(4);
            // 使用通道组
            // group = AsynchronousChannelGroup. withFixedThreadPool(service);
            // serverChannel = AsynchronousServerSocketChannel.open(group);
            // 开启服务端通道
            serverChannel = AsynchronousServerSocketChannel.open();  // 会绑定到默认通道组
            // 绑定监听接口
            serverChannel.bind(new InetSocketAddress(port));
            // 开始监听
            // public abstract <A> void accept(A attachment, CompletionHandler<AsynchronousSocketChannel,? super A> handler)
            // 在AIO中，监听是一个类似递归的操作——每次监听到客户端的请求后，都需要开启下一次的监听
            // 下一次监听需要服务器资源的支持，当前对象this含有最多的服务器资源
            log.debug("now in main");
            /**
             * 属类：AsynchronousServerSocketChannel
             * 方法：public abstract <A> void accept(A attachment,
             *                                 CompletionHandler<AsynchronousSocketChannel,? super A> handler)
             * 参数：attachment-附件，一般用当前对象
             *      handler-完成处理器
             * 返回：外部无返回，其实连接建立后内部获得AsynchronousSocketChannel对象
             * 作用：使用通道组线程池中的一个新线程去监听连接请求，无论连接建立成功或失败都会使用通道组线程池中的一个
             *      新线程去执行处理器。
             *      连接成功则会将得到的AsynchronousSocketChannel对象和附件传递给处理器，并执行处理器的completed()
             *      方法——在该线程开启下一次监听和其他操作（读或写）；连接失败则执行处理器的failed()方法。
             * 说明：
             *      为了实现高效处理新的连接请求（To allow for concurrent handling of new connections），监听连接
             *      请求和处理器的执行不在同一个线程，也就是无论连接建立成功或失败都会使用通道组线程池中的一个新线程去
             *      执行处理器。
             *
             *      新建立的AsynchronousSocketChannel连接也会绑定到和AsynchronousServerSocketChannel一样的通道组。
             */
            serverChannel.accept(this, new AIOServerHandler());  // 【非阻塞方法】
            // 由于上一步的accept是非阻塞的，继续执行代码！
            log.debug("now in main2");
            while (true){
                TimeUnit.SECONDS.sleep(30);  // 延时
                System.out.println("Time runs 30s.");
            }
//            TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);  // 延时
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new AIOServer(9999);
    }
}
